import axios, {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  AxiosError,
  InternalAxiosRequestConfig,
  RawAxiosRequestHeaders
} from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useUserStore } from '@/stores/user'
import router from '@/router'

/**
 * API响应接口
 */
export interface ApiResponse<T = any> {
  success: boolean
  data?: T
  error?: {
    code: string
    message: string
    details?: string
    validationErrors?: Array<{
      field: string
      message: string
      attemptedValue?: any
    }>
  }
  traceId?: string
  timestamp?: string
}

/**
 * HTTP客户端配置接口
 */
export interface HttpClientConfig {
  baseURL: string
  timeout?: number
  enableRetry?: boolean
  maxRetries?: number
  retryDelay?: number
  enableCache?: boolean
  cacheTime?: number
  enableLoading?: boolean
  enableErrorNotification?: boolean
}

/**
 * 请求拦截器配置
 */
export interface RequestInterceptorConfig {
  onFulfilled?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>
  onRejected?: (error: any) => any
}

/**
 * 响应拦截器配置
 */
export interface ResponseInterceptorConfig {
  onFulfilled?: (response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>
  onRejected?: (error: AxiosError) => any
}

/**
 * HTTP请求方法
 */
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'

/**
 * HTTP客户端类
 * 提供统一的HTTP请求处理、错误处理、重试机制等功能
 */
export class HttpClient {
  private instance: AxiosInstance
  private config: HttpClientConfig
  private requestCache = new Map<string, { data: any; timestamp: number }>()
  private pendingRequests = new Map<string, AbortController>()

  constructor(config: HttpClientConfig) {
    this.config = {
      timeout: 10000,
      enableRetry: true,
      maxRetries: 3,
      retryDelay: 1000,
      enableCache: false,
      cacheTime: 300000, // 5分钟
      enableLoading: true,
      enableErrorNotification: true,
      ...config
    }

    this.instance = axios.create({
      baseURL: this.config.baseURL,
      timeout: this.config.timeout,
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      }
    })

    this.setupInterceptors()
  }

  /**
   * 设置请求和响应拦截器
   */
  private setupInterceptors(): void {
    // 请求拦截器
    this.instance.interceptors.request.use(
      (config) => this.handleRequest(config),
      (error) => this.handleRequestError(error)
    )

    // 响应拦截器
    this.instance.interceptors.response.use(
      (response) => this.handleResponse(response),
      (error) => this.handleResponseError(error)
    )
  }

  /**
   * 处理请求
   */
  private handleRequest(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig {
    // 添加认证Token
    const userStore = useUserStore()
    if (userStore.token) {
      config.headers = {
        ...config.headers,
        'Authorization': `Bearer ${userStore.token}`
      } as RawAxiosRequestHeaders
    }

    // 添加请求ID
    config.headers = {
      ...config.headers,
      'X-Request-ID': this.generateRequestId(),
      'X-Client-Version': '1.0.0'
    } as RawAxiosRequestHeaders

    // 添加租户信息
    if (userStore.currentTenant?.id) {
      config.headers = {
        ...config.headers,
        'X-Tenant-ID': userStore.currentTenant.id.toString()
      } as RawAxiosRequestHeaders
    }

    // 处理重复请求
    const requestKey = this.getRequestKey(config)
    if (this.pendingRequests.has(requestKey)) {
      const controller = this.pendingRequests.get(requestKey)
      controller?.abort()
    }

    const controller = new AbortController()
    config.signal = controller.signal
    this.pendingRequests.set(requestKey, controller)

    // 开发环境下打印请求信息
    if (import.meta.env.DEV) {
      console.log(`🚀 HTTP Request: ${config.method?.toUpperCase()} ${config.url}`, {
        params: config.params,
        data: config.data,
        headers: config.headers
      })
    }

    return config
  }

  /**
   * 处理请求错误
   */
  private handleRequestError(error: any): Promise<never> {
    console.error('❌ Request Error:', error)
    return Promise.reject(error)
  }

  /**
   * 处理响应
   */
  private handleResponse(response: AxiosResponse): AxiosResponse {
    // 移除已完成的请求
    const requestKey = this.getRequestKey(response.config)
    this.pendingRequests.delete(requestKey)

    // 开发环境下打印响应信息
    if (import.meta.env.DEV) {
      console.log(`✅ HTTP Response: ${response.config.method?.toUpperCase()} ${response.config.url}`, {
        status: response.status,
        data: response.data,
        duration: response.headers['x-response-time']
      })
    }

    return response
  }

  /**
   * 处理响应错误
   */
  private async handleResponseError(error: AxiosError): Promise<never> {
    // 移除已完成的请求
    if (error.config) {
      const requestKey = this.getRequestKey(error.config)
      this.pendingRequests.delete(requestKey)
    }

    // 开发环境下打印错误信息
    if (import.meta.env.DEV) {
      console.error(`❌ HTTP Error: ${error.config?.method?.toUpperCase()} ${error.config?.url}`, {
        status: error.response?.status,
        data: error.response?.data,
        message: error.message
      })
    }

    // 处理网络错误和超时
    if (!error.response) {
      return this.handleNetworkError(error)
    }

    // 处理HTTP状态码错误
    return this.handleHttpError(error)
  }

  /**
   * 处理网络错误
   */
  private async handleNetworkError(error: AxiosError): Promise<never> {
    const isTimeout = error.code === 'ECONNABORTED'
    const isNetworkError = !error.response

    if (this.config.enableErrorNotification) {
      if (isTimeout) {
        ElMessage.error('请求超时，请稍后重试')
      } else if (isNetworkError) {
        ElMessage.error('网络连接失败，请检查网络设置')
      } else {
        ElMessage.error('网络错误，请稍后重试')
      }
    }

    // 如果启用重试且是网络错误，进行重试
    if (this.config.enableRetry && error.config && this.shouldRetry(error)) {
      return this.retryRequest(error.config)
    }

    return Promise.reject(this.transformError(error))
  }

  /**
   * 处理HTTP错误
   */
  private async handleHttpError(error: AxiosError): Promise<never> {
    const { status, data } = error.response!
    const responseData = data as ApiResponse

    switch (status) {
      case 401:
        return this.handleUnauthorizedError(error)

      case 403:
        return this.handleForbiddenError(error)

      case 404:
        return this.handleNotFoundError(error)

      case 422:
        return this.handleValidationError(error)

      case 429:
        return this.handleRateLimitError(error)

      case 500:
      case 502:
      case 503:
      case 504:
        return this.handleServerError(error)

      default:
        return this.handleDefaultError(error)
    }
  }

  /**
   * 处理401未授权错误
   */
  private async handleUnauthorizedError(error: AxiosError): Promise<never> {
    const userStore = useUserStore()

    if (this.config.enableErrorNotification) {
      ElMessage.error('登录已过期，请重新登录')
    }

    // 清除用户信息并跳转到登录页
    await userStore.logout()
    router.push('/login')

    return Promise.reject(this.transformError(error))
  }

  /**
   * 处理403禁止访问错误
   */
  private handleForbiddenError(error: AxiosError): Promise<never> {
    if (this.config.enableErrorNotification) {
      ElMessage.error('权限不足，无法访问此资源')
    }

    return Promise.reject(this.transformError(error))
  }

  /**
   * 处理404未找到错误
   */
  private handleNotFoundError(error: AxiosError): Promise<never> {
    if (this.config.enableErrorNotification) {
      ElMessage.error('请求的资源不存在')
    }

    return Promise.reject(this.transformError(error))
  }

  /**
   * 处理422验证错误
   */
  private handleValidationError(error: AxiosError): Promise<never> {
    const responseData = error.response?.data as ApiResponse

    if (this.config.enableErrorNotification && responseData?.error?.message) {
      ElMessage.error(responseData.error.message)
    }

    return Promise.reject(this.transformError(error))
  }

  /**
   * 处理429限流错误
   */
  private async handleRateLimitError(error: AxiosError): Promise<never> {
    if (this.config.enableErrorNotification) {
      ElMessage.warning('请求过于频繁，请稍后重试')
    }

    // 获取重试延迟时间
    const retryAfter = error.response?.headers['retry-after']
    const delay = retryAfter ? parseInt(retryAfter) * 1000 : 5000

    await new Promise(resolve => setTimeout(resolve, delay))

    if (this.config.enableRetry && error.config) {
      return this.retryRequest(error.config)
    }

    return Promise.reject(this.transformError(error))
  }

  /**
   * 处理服务器错误
   */
  private handleServerError(error: AxiosError): Promise<never> {
    if (this.config.enableErrorNotification) {
      ElMessage.error('服务器错误，请稍后重试')
    }

    // 如果启用重试，进行重试
    if (this.config.enableRetry && error.config && this.shouldRetry(error)) {
      return this.retryRequest(error.config)
    }

    return Promise.reject(this.transformError(error))
  }

  /**
   * 处理默认错误
   */
  private handleDefaultError(error: AxiosError): Promise<never> {
    if (this.config.enableErrorNotification) {
      ElMessage.error('请求失败，请稍后重试')
    }

    return Promise.reject(this.transformError(error))
  }

  /**
   * 转换错误格式
   */
  private transformError(error: AxiosError): {
    code: string;
    message: string;
    details?: string;
    originalError: AxiosError
  } {
    const responseData = error.response?.data as ApiResponse

    return {
      code: responseData?.error?.code || `HTTP_${error.response?.status || 'UNKNOWN'}`,
      message: responseData?.error?.message || error.message || '未知错误',
      details: responseData?.error?.details,
      originalError: error
    }
  }

  /**
   * 判断是否应该重试
   */
  private shouldRetry(error: AxiosError): boolean {
    const status = error.response?.status
    const method = error.config?.method?.toUpperCase()

    // 只对GET请求和部分状态码进行重试
    const retryableStatuses = [408, 429, 500, 502, 503, 504]
    const retryableMethods = ['GET', 'HEAD', 'OPTIONS']

    return retryableMethods.includes(method || '') &&
           (!status || retryableStatuses.includes(status))
  }

  /**
   * 重试请求
   */
  private async retryRequest(config: InternalAxiosRequestConfig): Promise<any> {
    const retryCount = (config as any).__retryCount || 0

    if (retryCount >= this.config.maxRetries!) {
      return Promise.reject(new Error(`重试次数超过限制 (${this.config.maxRetries})`))
    }

    // 增加重试计数
    ;(config as any).__retryCount = retryCount + 1

    // 计算延迟时间（指数退避）
    const delay = this.config.retryDelay! * Math.pow(2, retryCount)
    await new Promise(resolve => setTimeout(resolve, delay))

    return this.instance(config)
  }

  /**
   * 生成请求ID
   */
  private generateRequestId(): string {
    return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
  }

  /**
   * 获取请求键
   */
  private getRequestKey(config: InternalAxiosRequestConfig): string {
    const { method, url, params, data } = config
    return `${method}-${url}-${JSON.stringify(params)}-${JSON.stringify(data)}`
  }

  /**
   * GET请求
   */
  async get<T = any>(
    url: string,
    params?: any,
    config?: AxiosRequestConfig
  ): Promise<ApiResponse<T>> {
    return this.request<T>('GET', url, { params, ...config })
  }

  /**
   * POST请求
   */
  async post<T = any>(
    url: string,
    data?: any,
    config?: AxiosRequestConfig
  ): Promise<ApiResponse<T>> {
    return this.request<T>('POST', url, { data, ...config })
  }

  /**
   * PUT请求
   */
  async put<T = any>(
    url: string,
    data?: any,
    config?: AxiosRequestConfig
  ): Promise<ApiResponse<T>> {
    return this.request<T>('PUT', url, { data, ...config })
  }

  /**
   * DELETE请求
   */
  async delete<T = any>(
    url: string,
    config?: AxiosRequestConfig
  ): Promise<ApiResponse<T>> {
    return this.request<T>('DELETE', url, config)
  }

  /**
   * PATCH请求
   */
  async patch<T = any>(
    url: string,
    data?: any,
    config?: AxiosRequestConfig
  ): Promise<ApiResponse<T>> {
    return this.request<T>('PATCH', url, { data, ...config })
  }

  /**
   * 通用请求方法
   */
  async request<T = any>(
    method: HttpMethod,
    url: string,
    config: AxiosRequestConfig = {}
  ): Promise<ApiResponse<T>> {
    const requestConfig: AxiosRequestConfig = {
      method,
      url,
      ...config
    }

    // 检查缓存
    if (this.config.enableCache && method === 'GET') {
      const cacheKey = `${method}-${url}-${JSON.stringify(config.params)}`
      const cached = this.requestCache.get(cacheKey)

      if (cached && Date.now() - cached.timestamp < this.config.cacheTime!) {
        return cached.data
      }
    }

    try {
      const response = await this.instance.request<ApiResponse<T>>(requestConfig)
      const result = response.data

      // 缓存GET请求结果
      if (this.config.enableCache && method === 'GET' && result.success) {
        const cacheKey = `${method}-${url}-${JSON.stringify(config.params)}`
        this.requestCache.set(cacheKey, {
          data: result,
          timestamp: Date.now()
        })
      }

      return result
    } catch (error) {
      throw error
    }
  }

  /**
   * 上传文件
   */
  async upload<T = any>(
    url: string,
    file: File | FormData,
    config?: AxiosRequestConfig
  ): Promise<ApiResponse<T>> {
    const formData = file instanceof FormData ? file : new FormData()
    if (file instanceof File) {
      formData.append('file', file)
    }

    const uploadConfig: AxiosRequestConfig = {
      method: 'POST',
      url,
      data: formData,
      headers: {
        'Content-Type': 'multipart/form-data'
      },
      timeout: 300000, // 5分钟上传超时
      onUploadProgress: config?.onUploadProgress,
      ...config
    }

    const response = await this.instance.request<ApiResponse<T>>(uploadConfig)
    return response.data
  }

  /**
   * 下载文件
   */
  async download(
    url: string,
    filename?: string,
    config?: AxiosRequestConfig
  ): Promise<void> {
    const downloadConfig: AxiosRequestConfig = {
      method: 'GET',
      url,
      responseType: 'blob',
      ...config
    }

    const response = await this.instance.request(downloadConfig)

    // 创建下载链接
    const blob = new Blob([response.data])
    const downloadUrl = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = downloadUrl
    link.download = filename || 'download'
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(downloadUrl)
  }

  /**
   * 取消所有待处理的请求
   */
  cancelAllRequests(): void {
    this.pendingRequests.forEach((controller) => {
      controller.abort()
    })
    this.pendingRequests.clear()
  }

  /**
   * 清除缓存
   */
  clearCache(): void {
    this.requestCache.clear()
  }
}

/**
 * 创建默认的HTTP客户端实例
 */
export function createHttpClient(config: Partial<HttpClientConfig> = {}): HttpClient {
  const baseURL = import.meta.env.VITE_API_BASE_URL || '/api'

  return new HttpClient({
    baseURL,
    ...config
  })
}

// 导出默认实例
export const httpClient = createHttpClient()